package com.lobstar.xrpc.processor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

import com.lobstar.xrpc.client.main.MainClient;
import com.lobstar.xrpc.common.ClientCallable;
import com.lobstar.xrpc.common.ServerCallable;
import com.lobstar.xrpc.server.main.MainServer;
import com.lobstar.xrpc.service.annotation.Call;
import com.lobstar.xrpc.service.annotation.SParam;
import com.lobstar.xrpc.tools.Fields;

public class ServiceProcessor {

	@SuppressWarnings("unchecked")
	public static <T> T buildServiceByClient(MainClient client,Class<T> serivceInterfaceClz) {
		if(!serivceInterfaceClz.isInterface()) {
			throw new RuntimeException("service not interface");
		}
		return (T) Proxy.newProxyInstance(ServiceProcessor.class.getClassLoader(),new Class[] {serivceInterfaceClz},new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				Type returnType = method.getGenericReturnType();
				String methodName = method.getName();
				Call callDef = method.getAnnotation(Call.class);
				if(callDef != null) {
					methodName = callDef.value();
				}
				Parameter[] parameters = method.getParameters();
				Fields fields = Fields.build();
				for (int i = 0;i<parameters.length;i++) {
					String parameterName = String.valueOf(i);
					SParam paramDef = parameters[i].getAnnotation(SParam.class);
					if(paramDef!=null) {
						parameterName = paramDef.value();
					}
					fields.field(parameterName, args[i]);
				}
				if(returnType == void.class) {
					client.asyncCall(methodName, fields);
				}else {
					return client.asyncCall(methodName, fields, returnType);
				}
				return null;
			}
		});
	}

	@SuppressWarnings("unchecked")
	public static <T> T buildServiceByServer(MainServer server,String targetClient,Class<T> serivceInterfaceClz) {
		if(!serivceInterfaceClz.isInterface()) {
			throw new RuntimeException("service not interface");
		}
		return (T) Proxy.newProxyInstance(ServiceProcessor.class.getClassLoader(),new Class[] {serivceInterfaceClz},new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				Type returnType = method.getGenericReturnType();
				String methodName = method.getName();
				Call callDef = method.getAnnotation(Call.class);
				if(callDef != null) {
					methodName = callDef.value();
				}
				Parameter[] parameters = method.getParameters();
				Fields fields = Fields.build();
				for (int i = 0;i<parameters.length;i++) {
					String parameterName = parameters[i].getName();
					SParam paramDef = parameters[i].getAnnotation(SParam.class);
					if(paramDef!=null) {
						parameterName = paramDef.value();
					}
					fields.field(parameterName, args[i]);
				}
				if(returnType == void.class) {
					server.asyncCall(targetClient,methodName, fields);
				}else {
					return server.asyncCall(targetClient,methodName, fields, returnType);
				}
				return null;
			}
		});
	}

	public static void main(String[] args) {
		A a = buildServiceByClient(null,A.class);
		a.sss();
	}

	static interface A extends B{
		public void sss();
		public int ttt();
	}
	static interface B {
		public void gg();
	}
}
